package cn.tedu.charging.device.warm;

import cn.tedu.charging.common.pojo.po.ChargingStationPO;
import cn.tedu.charging.device.mapper.StationMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.dao.DataAccessException;
import org.springframework.data.geo.Point;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@Slf4j
public class StationWarmUP implements ApplicationRunner {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private StationMapper stationMapper;
    @Override
    public void run(ApplicationArguments args) throws Exception {
        log.info("开始预热...");
        //1.checkLock 有锁则结束 无锁则执行预热
        Boolean isContinuable=checkLock();
        if (!isContinuable){
            log.info("多次执行预热，不在执行直接返回");
            return;
        }
        //2.读取数据库数据 按照批次读取 每次1000条
        batchWarmUp(1000l);//制定一个batchSize=1000
    }

    private void batchWarmUp(long batchSize) {
        //1.读取total
        Long total=stationMapper.selectCount(null);//获取总数
        //2.计算循环次数
        Long loopSize=total%batchSize==0?total/batchSize:total/batchSize+1;
        for(long i=0l;i<loopSize;i++){
            //第一批 i=0 limit 0,1000
            //第二批 i=1 limit 1000,1000
            //第三批 i=2 limit 2000,1000
            //select * from stations limit #{start},#{size}
            QueryWrapper<ChargingStationPO> query=new QueryWrapper<>();
            query.last("limit "+i*batchSize+","+batchSize);//sql末尾 拼接的一些语法
            List<ChargingStationPO> pos = stationMapper.selectList(query);
            //3.循环遍历写入geo和string 增强for循环
            List results = redisTemplate.executePipelined(new SessionCallback<Object>() {
                @Override
                public <K, V> Object execute(RedisOperations<K, V> operations) throws DataAccessException {
                    //set get
                    for (ChargingStationPO po : pos) {
                        saveStringStationCache(po);
                        saveGeoStationId(po);
                    }
                    return null;
                }
            });

        }
    }

    private void saveStringStationCache(ChargingStationPO po) {
        //set charging:station:cache:stationId po
        ValueOperations stringOps = redisTemplate.opsForValue();
        String stationCacheKey="charging:stations:detail:"+po.getId();
        stringOps.set(stationCacheKey,po);
    }

    private void saveGeoStationId(ChargingStationPO po) {
        String stationGeoKey="charging:all:stations";
        //geoadd lng lat stationId
        GeoOperations geoOps = redisTemplate.opsForGeo();
        geoOps.add(stationGeoKey,
                new Point(
                po.getStationLng().doubleValue(),
                po.getStationLat().doubleValue()),
                po.getId());
    }

    private Boolean checkLock() {
        String warmUpLock="charging:warm:up.lock";//最好放常量
        //setnx key value 返回1成功 0失败
        return redisTemplate.opsForValue().setIfAbsent(warmUpLock, "1");
    }
}
